package nessie;

/**
 * this class emulates the CPU instructions(with a rudimentary[whimsy] cycle
 * counter). without this class, you're toast.
 * in hopes of implementing multi-threading, this is the only hardware emulation
 * class that doesn't contain static methods
 */
public class CPU {

    /**
     * ADC AND ASL BCC BCS BEQ BIT BMI BNE BPL BRK BVC BVS CLC CLD CLI CLV CMP
     * CPX CPY DEC DEX DEY EOR INC INX INY JMP JSR LDA LDX LDY LSR NOP ORA PHA
     * PHP PLA PLP ROL ROR RTI RTS SBC SEC SED SEI STA STX STY TAX TAY TSX TXA
     * TXS TYA
     * plus some undocumented stuff that is apparently never used.
     */
    public static boolean skipInstruction = false;
    public int cyclone, turnThePage;

    /**
     * read and execute opcodes
     * @param opcode
     * @throws Exception
     */
    public void exec(byte opcode) throws Exception {
        //TODO:add dummy writes, they read the original value, write it to the function(flags), and then write the new value
        switch (opcode & 0xFF) {//unsign
            /**
             * <editor-fold defaultstate="collapsed" desc="ADC">
             *******
             */
            case 0x69://immediate
                ADC(Memory.MODE_IMMEDIATE());
                cyclone += 2;
                break;
            case 0x65://zero page
                ADC(Memory.MODE_ZERO_PAGE());
                cyclone += 3;
                break;
            case 0x75://zero page X
                ADC(Memory.MODE_ZERO_PAGE_X());
                cyclone += 4;
                break;
            case 0x6D://absolute
                ADC(Memory.MODE_ABSOLUTE());
                cyclone += 4;
                break;
            case 0x7D://absolute x
                ADC(Memory.MODE_ABSOLUTE_X());
                cyclone += (4 + Memory.getPageCrossCycles(turnThePage = 1));
                break;
            case 0x79://absolute y
                ADC(Memory.MODE_ABSOLUTE_Y());
                cyclone += (4 + Memory.getPageCrossCycles(turnThePage = 1));
                break;
            case 0x61://indexed indirect addressX
                ADC(Memory.MODE_INDIRECT_X());
                cyclone += 6;
                break;
            case 0x71://indirect indexed addressY
                ADC(Memory.MODE_INDIRECT_Y());
                cyclone += (5 + Memory.getPageCrossCycles(turnThePage = 1));
                break;
            /**
             * ******
             * </editor-fold>
             */
            /**
             * <editor-fold defaultstate="collapsed" desc="AND">
             *******
             */
            case 0x29://immediate
                AND(Memory.MODE_IMMEDIATE());
                cyclone += 2;
                break;
            case 0x25://zero page
                AND(Memory.MODE_ZERO_PAGE());
                cyclone += 3;
                break;
            case 0x35://zero page X
                AND(Memory.MODE_ZERO_PAGE_X());
                cyclone += 4;
                break;
            case 0x2D://absolute
                AND(Memory.MODE_ABSOLUTE());
                cyclone += 4;
                break;
            case 0x3D://absolute x
                AND(Memory.MODE_ABSOLUTE_X());
                cyclone += (4 + Memory.getPageCrossCycles(turnThePage = 1));
                break;
            case 0x39://absolute y
                AND(Memory.MODE_ABSOLUTE_Y());
                cyclone += (4 + Memory.getPageCrossCycles(turnThePage = 1));
                break;
            case 0x21://indexed indirect addressX
                AND(Memory.MODE_INDIRECT_X());
                cyclone += 6;
                break;
            case 0x31://indirect indexed addressY
                AND(Memory.MODE_INDIRECT_Y());
                cyclone += (5 + Memory.getPageCrossCycles(turnThePage = 1));
                break;
            /**
             * ******
             * </editor-fold>
             */
            /**
             * <editor-fold defaultstate="collapsed" desc="ASL">
             *******
             */
            case 0x0A://accumulator
                MODE_ACCUMULATOR = true;
                ASL(Memory.MODE_ACCUMULATOR());
                cyclone += 2;
                break;
            case 0x06://zero page
                ASL(Memory.ADDRESS_ZERO_PAGE());
                cyclone += 5;
                break;
            case 0x16://zero page X
                ASL(Memory.ADDRESS_ZERO_PAGE_X());
                cyclone += 6;
                break;
            case 0x0E://absolute
                ASL(Memory.ADDRESS_ABSOLUTE());
                cyclone += 6;
                break;
            case 0x1E://absolute x
                ASL(Memory.ADDRESS_ABSOLUTE_X());
                cyclone += 7;
                break;
            /**
             * ******
             * </editor-fold>
             */
            /**
             * <editor-fold defaultstate="collapsed" desc="BIT">
             *******
             */
            case 0x2C://absolute
                BIT(Memory.MODE_ABSOLUTE());
                cyclone += 4;
                break;
            case 0x24://zero page
                BIT(Memory.MODE_ZERO_PAGE());
                cyclone += 3;
                break;
            /**
             * ******
             * </editor-fold>
             */
            /**
             * <editor-fold defaultstate="collapsed" desc="BRANCH">
             *******
             */
            case 0x90://relative
                BCC(Memory.MODE_RELATIVE());
                cyclone += (2 + Memory.getPageCrossCycles(turnThePage = 2));
                break;
            case 0xB0://relative
                BCS(Memory.MODE_RELATIVE());
                cyclone += (2 + Memory.getPageCrossCycles(turnThePage = 2));
                break;
            case 0xF0://relative
                BEQ(Memory.MODE_RELATIVE());
                cyclone += (2 + Memory.getPageCrossCycles(turnThePage = 2));
                break;
            case 0x30://relative
                BMI(Memory.MODE_RELATIVE());
                cyclone += (2 + Memory.getPageCrossCycles(turnThePage = 2));
                break;
            case 0xD0://relative
                BNE(Memory.MODE_RELATIVE());
                cyclone += (2 + Memory.getPageCrossCycles(turnThePage = 2));
                break;
            case 0x10://relative
                BPL(Memory.MODE_RELATIVE());
                cyclone += (2 + Memory.getPageCrossCycles(turnThePage = 2));
                break;
            case 0x50://relative
                BVC(Memory.MODE_RELATIVE());
                cyclone += (2 + Memory.getPageCrossCycles(turnThePage = 2));
                break;
            case 0x70://relative
                BVS(Memory.MODE_RELATIVE());
                cyclone += (2 + Memory.getPageCrossCycles(turnThePage = 2));
                break;
            /**
             * ******
             * </editor-fold>
             */
            /**
             * BRK
             *******
             */
            case 0x00://implied
                BRK();
                cyclone += 7;
                break;
            /**
             * ******
             * end BRK
             */
            /**
             * <editor-fold defaultstate="collapsed" desc="CLEAR/SET">
             *******
             */
            case 0x18://implied
                CLC();
                cyclone += 2;
                break;
            case 0x38://implied
                SEC();
                cyclone += 2;
                break;
            case 0x58://implied
                CLI();
                cyclone += 2;
                break;
            case 0x78://implied
                SEI();
                cyclone += 2;
                break;
            case 0xB8://implied
                CLV();
                cyclone += 2;
                break;
            case 0xD8://implied
                CLD();
                cyclone += 2;
                break;
            case 0xF8://implied
                SED();
                cyclone += 2;
                break;
            /**
             * ******
             * </editor-fold>
             */
            /**
             * <editor-fold defaultstate="collapsed" desc="CMP">
             *******
             */
            case 0xC9://immediate
                CMP(Memory.MODE_IMMEDIATE());
                cyclone += 2;
                break;
            case 0xC5://zero page
                CMP(Memory.MODE_ZERO_PAGE());
                cyclone += 3;
                break;
            case 0xD5://zero page X
                CMP(Memory.MODE_ZERO_PAGE_X());
                cyclone += 4;
                break;
            case 0xCD://absolute
                CMP(Memory.MODE_ABSOLUTE());
                cyclone += 4;
                break;
            case 0xDD://absolute x
                CMP(Memory.MODE_ABSOLUTE_X());
                cyclone += (4 + Memory.getPageCrossCycles(turnThePage = 1));
                break;
            case 0xD9://absolute y
                CMP(Memory.MODE_ABSOLUTE_Y());
                cyclone += (4 + Memory.getPageCrossCycles(turnThePage = 1));
                break;
            case 0xC1://indexed indirect addressX
                CMP(Memory.MODE_INDIRECT_X());
                cyclone += 6;
                break;
            case 0xD1://indirect indexed addressY
                CMP(Memory.MODE_INDIRECT_Y());
                cyclone += (5 + Memory.getPageCrossCycles(turnThePage = 1));
                break;
            /**
             * ******
             * </editor-fold>
             */
            /**
             * <editor-fold defaultstate="collapsed" desc="CPX">
             *******
             */
            case 0xE0://immediate
                CPX(Memory.MODE_IMMEDIATE());
                cyclone += 2;
                break;
            case 0xE4://zero page
                CPX(Memory.MODE_ZERO_PAGE());
                cyclone += 3;
                break;
            case 0xEC://absolute
                CPX(Memory.MODE_ABSOLUTE());
                cyclone += 4;
                break;
            /**
             * ******
             * </editor-fold>
             */
            /**
             * <editor-fold defaultstate="collapsed" desc="CPY">
             *******
             */
            case 0xC0://immediate
                CPY(Memory.MODE_IMMEDIATE());
                cyclone += 2;
                break;
            case 0xC4://zero page
                CPY(Memory.MODE_ZERO_PAGE());
                cyclone += 3;
                break;
            case 0xCC://absolute
                CPY(Memory.MODE_ABSOLUTE());
                cyclone += 4;
                break;
            /**
             * ******
             * </editor-fold>
             */
            /**
             * <editor-fold defaultstate="collapsed" desc="DEC">
             *******
             */
            case 0xC6://zero page
                DEC(Memory.ADDRESS_ZERO_PAGE());
                cyclone += 5;
                break;
            case 0xD6://zero page X
                DEC(Memory.ADDRESS_ZERO_PAGE_X());
                cyclone += 6;
                break;
            case 0xCE://absolute
                DEC(Memory.ADDRESS_ABSOLUTE());
                cyclone += 6;
                break;
            case 0xDE://absolute X
                DEC(Memory.ADDRESS_ABSOLUTE_X());
                cyclone += 7;
                break;
            /**
             * ******
             * </editor-fold>
             */
            /**
             * <editor-fold defaultstate="collapsed" desc="EOR">
             *******
             */
            case 0x49://immediate
                EOR(Memory.MODE_IMMEDIATE());
                cyclone += 2;
                break;
            case 0x45://zero page
                EOR(Memory.MODE_ZERO_PAGE());
                cyclone += 3;
                break;
            case 0x55://zero page X
                EOR(Memory.MODE_ZERO_PAGE_X());
                cyclone += 4;
                break;
            case 0x4D://absolute
                EOR(Memory.MODE_ABSOLUTE());
                cyclone += 4;
                break;
            case 0x5D://absolute X
                EOR(Memory.MODE_ABSOLUTE_X());
                cyclone += (4 + Memory.getPageCrossCycles(turnThePage = 1));
                break;
            case 0x59://absolute Y
                EOR(Memory.MODE_ABSOLUTE_Y());
                cyclone += (4 + Memory.getPageCrossCycles(turnThePage = 1));
                break;
            case 0x41://indirect X
                EOR(Memory.MODE_INDIRECT_X());
                cyclone += 6;
                break;
            case 0x51://indirect Y
                EOR(Memory.MODE_INDIRECT_Y());
                cyclone += (5 + Memory.getPageCrossCycles(turnThePage = 1));
                break;
            /**
             * ******
             * </editor-fold>
             */
            /**
             * <editor-fold defaultstate="collapsed" desc="INC">
             *******
             */
            case 0xE6://zero page
                INC(Memory.ADDRESS_ZERO_PAGE());
                cyclone += 5;
                break;
            case 0xF6://zero page X
                INC(Memory.ADDRESS_ZERO_PAGE_X());
                cyclone += 6;
                break;
            case 0xEE://absolute
                INC(Memory.ADDRESS_ABSOLUTE());
                cyclone += 6;
                break;
            case 0xFE://absolute X
                INC(Memory.ADDRESS_ABSOLUTE_X());
                cyclone += 7;
                break;
            /**
             * ******
             * </editor-fold>
             */
            /**
             * <editor-fold defaultstate="collapsed" desc="JMP">
             *******
             */
            case 0x4C://absolute
                JMP(Memory.ADDRESS_ABSOLUTE());
                cyclone += 3;
                break;
            case 0x6C://indirect
                JMP(Memory.MODE_INDIRECT());
                cyclone += 5;
                break;
            /**
             * ******
             * </editor-fold>
             */
            /**
             * JSR
             *******
             */
            case 0x20://absolute
                JSR(Memory.ADDRESS_ABSOLUTE());
                cyclone += 6;
                break;
            /**
             * ******
             * end JSR
             */
            /**
             * <editor-fold defaultstate="collapsed" desc="LDA">
             *******
             */
            case 0xA9://immediate
                LDA(Memory.MODE_IMMEDIATE());
                cyclone += 6;
                break;
            case 0xA5://zero page
                LDA(Memory.MODE_ZERO_PAGE());
                cyclone += 3;
                break;
            case 0xB5://zero page X
                LDA(Memory.MODE_ZERO_PAGE_X());
                cyclone += 4;
                break;
            case 0xAD://absolute
                LDA(Memory.MODE_ABSOLUTE());
                cyclone += 4;
                break;
            case 0xBD://absolute X
                LDA(Memory.MODE_ABSOLUTE_X());
                cyclone += (4 + Memory.getPageCrossCycles(turnThePage = 1));
                break;
            case 0xB9://absolute Y
                LDA(Memory.MODE_ABSOLUTE_Y());
                cyclone += (4 + Memory.getPageCrossCycles(turnThePage = 1));
                break;
            case 0xA1://indirect X
                LDA(Memory.MODE_INDIRECT_X());
                cyclone += 6;
                break;
            case 0xB1://indirect Y
                LDA(Memory.MODE_INDIRECT_Y());
                cyclone += (5 + Memory.getPageCrossCycles(turnThePage = 1));
                break;
            /**
             * ******
             * </editor-fold>
             */
            /**
             * <editor-fold defaultstate="collapsed" desc="LDX">
             *******
             */
            case 0xA2://immediate
                LDX(Memory.MODE_IMMEDIATE());
                cyclone += 2;
                break;
            case 0xA6://zero page
                LDX(Memory.MODE_ZERO_PAGE());
                cyclone += 3;
                break;
            case 0xB6://zero page Y
                LDX(Memory.MODE_ZERO_PAGE_Y());
                cyclone += 4;
                break;
            case 0xAE://absolute
                LDX(Memory.MODE_ABSOLUTE());
                cyclone += 4;
                break;
            case 0xBE://absolute Y
                LDX(Memory.MODE_ABSOLUTE_Y());
                cyclone += (4 + Memory.getPageCrossCycles(turnThePage = 1));
                break;
            /**
             * ******
             * </editor-fold>
             */
            /**
             * <editor-fold defaultstate="collapsed" desc="LDY">
             *******
             */
            case 0xA0://immediate
                LDY(Memory.MODE_IMMEDIATE());
                cyclone += 2;
                break;
            case 0xA4://zero page
                LDY(Memory.MODE_ZERO_PAGE());
                cyclone += 3;
                break;
            case 0xB4://zero page X
                LDY(Memory.MODE_ZERO_PAGE_X());
                cyclone += 4;
                break;
            case 0xAC://absolute
                LDY(Memory.MODE_ABSOLUTE());
                cyclone += 4;
                break;
            case 0xBC://absolute X
                LDY(Memory.MODE_ABSOLUTE_X());
                cyclone += (4 + Memory.getPageCrossCycles(turnThePage = 1));
                break;
            /**
             * ******
             * </editor-fold>
             */
            /**
             * <editor-fold defaultstate="collapsed" desc="LSR">
             *******
             */
            case 0x4A://accumulator
                MODE_ACCUMULATOR = true;
                LSR(Memory.MODE_ACCUMULATOR());
                cyclone += 2;
                break;
            case 0x46://zero page
                LSR(Memory.ADDRESS_ZERO_PAGE());
                cyclone += 5;
                break;
            case 0x56://zero page X
                LSR(Memory.ADDRESS_ZERO_PAGE_X());
                cyclone += 6;
                break;
            case 0x4E://absolute
                LSR(Memory.ADDRESS_ABSOLUTE());
                cyclone += 6;
                break;
            case 0x5E://absolute X
                LSR(Memory.ADDRESS_ABSOLUTE_X());
                cyclone += 7;
                break;
            /**
             * ******
             * </editor-fold>
             */
            /**
             * <editor-fold defaultstate="collapsed" desc="NOP">
             *******
             */
            case 0x1A:
            case 0x3A:
            case 0x5A:
            case 0x7A:
            case 0xDA://harvey dent!
            case 0xFA:
            case 0xEA:
                NOP();
                cyclone += 2;
                break;
            //triple NOP
            case 0x0C:
            case 0x1C:
            case 0x3C:
            case 0x5C:
            case 0x7C:
            case 0xDC:
            case 0xFC:
                NOP();
            //double NOP
            case 0x80:
            case 0x82:
            case 0x89:
            case 0xC2:
            case 0xE2:
                DOP();
                cyclone += 2;
                break;
            case 0x04:
            case 0x44:
            case 0x64:
                DOP();
                cyclone += 3;
                break;
            case 0x14:
            case 0x34:
            case 0x54:
            case 0xD4:
            case 0xF4:
            case 0x74:
                DOP();
                cyclone += 4;
                break;
            /**
             * ******
             * </editor-fold>
             */
            /**
             * <editor-fold defaultstate="collapsed" desc="ORA">
             *******
             */
            case 0x09://immediate
                ORA(Memory.MODE_IMMEDIATE());
                cyclone += 2;
                break;
            case 0x05://zero page
                ORA(Memory.MODE_ZERO_PAGE());
                cyclone += 3;
                break;
            case 0x15://zero page X
                ORA(Memory.MODE_ZERO_PAGE_X());
                cyclone += 4;
                break;
            case 0x0D://absolute
                ORA(Memory.MODE_ABSOLUTE());
                cyclone += 4;
                break;
            case 0x1D://absolute X
                ORA(Memory.MODE_ABSOLUTE_X());
                cyclone += 4;
                turnThePage = 1;
                break;
            case 0x19://absolute Y
                ORA(Memory.MODE_ABSOLUTE_Y());
                cyclone += 4;
                turnThePage = 1;
                break;
            case 0x01://indirect X
                ORA(Memory.MODE_INDIRECT_X());
                cyclone += 6;
                break;
            case 0x11://indirect Y
                ORA(Memory.MODE_INDIRECT_Y());
                cyclone += 5;
                turnThePage = 1;
                break;
            /**
             * ******
             * </editor-fold>
             */
            /**
             * <editor-fold defaultstate="collapsed" desc="Stack Instructions">
             *******
             */
            case 0x48://implied
                PHA();
                cyclone += 3;
                break;
            case 0x68://implied
                PLA();
                cyclone += 4;
                break;
            case 0x08://implied
                PHP();
                cyclone += 3;
                break;
            case 0x28://implied
                PLP();
                cyclone += 4;
                break;
            case 0x9A://implied
                TXS();
                cyclone += 2;
                break;
            case 0xBA://implied
                TSX();
                cyclone += 6;
                break;
            /**
             * ******
             * </editor-fold>
             */
            /**
             * <editor-fold defaultstate="collapsed" desc="Register
             * Instructions">
             *******
             */
            case 0xCA://implied
                DEX();
                cyclone += 2;
                break;
            case 0x88://implied
                DEY();
                cyclone += 2;
                break;
            case 0xE8://implied
                INX();
                cyclone += 2;
                break;
            case 0xC8://implied
                INY();
                cyclone += 2;
                break;
            case 0xAA://implied
                TAX();
                cyclone += 2;
                break;
            case 0xA8://implied
                TAY();
                cyclone += 2;
                break;
            case 0x8A://implied
                TXA();
                cyclone += 2;
                break;
            case 0x98://implied
                TYA();
                cyclone += 2;
                break;
            /**
             * ******
             * </editor-fold>
             */
            /**
             * <editor-fold defaultstate="collapsed" desc="ROL">
             *******
             */
            case 0x2A://accumulator
                MODE_ACCUMULATOR = true;
                ROL(Memory.MODE_ACCUMULATOR());
                cyclone += 2;
                break;
            case 0x26://zero page
                ROL(Memory.ADDRESS_ZERO_PAGE());
                cyclone += 5;
                break;
            case 0x36://zero page X
                ROL(Memory.ADDRESS_ZERO_PAGE_X());
                cyclone += 6;
                break;
            case 0x2E://absolute
                ROL(Memory.ADDRESS_ABSOLUTE());
                cyclone += 6;
                break;
            case 0x3E://absolute X
                ROL(Memory.ADDRESS_ABSOLUTE_X());
                cyclone += 7;
                break;
            /**
             * ******
             * </editor-fold>
             */
            /**
             * <editor-fold defaultstate="collapsed" desc="ROR">
             *******
             */
            case 0x6A://accumulator
                MODE_ACCUMULATOR = true;
                ROR(Memory.MODE_ACCUMULATOR());
                cyclone += 2;
                break;
            case 0x66://zero page
                ROR(Memory.ADDRESS_ZERO_PAGE());
                cyclone += 5;
                break;
            case 0x76://zero page X
                ROR(Memory.ADDRESS_ZERO_PAGE_X());
                cyclone += 6;
                break;
            case 0x6E://absolute
                ROR(Memory.ADDRESS_ABSOLUTE());
                cyclone += 6;
                break;
            case 0x7E://absolute X
                ROR(Memory.ADDRESS_ABSOLUTE_X());
                cyclone += 7;
                break;
            /**
             * ******
             * </editor-fold>
             */
            /**
             * RTI
             *******
             */
            case 0x40://implied
                RTI();
                cyclone += 6;
                break;
            /**
             * ******
             * end RTI
             */
            /**
             * RTS
             *******
             */
            case 0x60://implied
                RTS();
                cyclone += 6;
                break;
            /**
             * ******
             * end RTS
             */
            /**
             * <editor-fold defaultstate="collapsed" desc="SBC">
             *******
             */
            case 0xEB://undocumented opcode
            case 0xE9://immediate
                SBC(Memory.MODE_IMMEDIATE());
                cyclone += 2;
                break;
            case 0xE5://zero page
                SBC(Memory.MODE_ZERO_PAGE());
                cyclone += 3;
                break;
            case 0xF5://zero page X
                SBC(Memory.MODE_ZERO_PAGE_X());
                cyclone += 4;
                break;
            case 0xED://absolute
                SBC(Memory.MODE_ABSOLUTE());
                cyclone += 4;
                break;
            case 0xFD://absolute X
                SBC(Memory.MODE_ABSOLUTE_X());
                cyclone += (4 + Memory.getPageCrossCycles(turnThePage = 1));
                break;
            case 0xF9://absolute Y
                SBC(Memory.MODE_ABSOLUTE_Y());
                cyclone += (4 + Memory.getPageCrossCycles(turnThePage = 1));
                break;
            case 0xE1://indirect X
                SBC(Memory.MODE_INDIRECT_X());
                cyclone += 6;
                break;
            case 0xF1://indirect Y
                SBC(Memory.MODE_INDIRECT_Y());
                cyclone += (5 + Memory.getPageCrossCycles(turnThePage = 1));
                break;
            /**
             * ******
             * </editor-fold>
             */
            /**
             * <editor-fold defaultstate="collapsed" desc="STA">
             *******
             */
            case 0x85://zero page
                STA(Memory.ADDRESS_ZERO_PAGE());
                cyclone += 3;
                break;
            case 0x95://zero page X
                STA(Memory.ADDRESS_ZERO_PAGE_X());
                cyclone += 4;
                break;
            case 0x8D://absolute
                STA(Memory.ADDRESS_ABSOLUTE());
                cyclone += 4;
                break;
            case 0x9D://absolute X
                STA(Memory.ADDRESS_ABSOLUTE_X());
                cyclone += 5;
//                short ADDRESS_ABSOLUTE_X_DUMMY_READ = Memory.ADDRESS_ABSOLUTE_X_DUMMY_READ();
//                if (skipInstruction == false) {
//                    STA(ADDRESS_ABSOLUTE_X_DUMMY_READ);
//                }
//                skipInstruction = false;
                break;
            case 0x99://absolute Y
                STA(Memory.ADDRESS_ABSOLUTE_Y());
                cyclone += 5;
                break;
            case 0x81://indirect X
                STA(Memory.ADDRESS_INDIRECT_X());
                cyclone += 6;
                break;
            case 0x91://indirect Y
                STA(Memory.ADDRESS_INDIRECT_Y());
                cyclone += 6;
                break;
            /**
             * ******
             * </editor-fold>
             */
            /**
             * <editor-fold defaultstate="collapsed" desc="STX">
             *******
             */
            case 0x86://zero page
                STX(Memory.ADDRESS_ZERO_PAGE());
                cyclone += 3;
                break;
            case 0x96://zero page y
                STX(Memory.ADDRESS_ZERO_PAGE_Y());
                cyclone += 4;
                break;
            case 0x8E://absolute
                STX(Memory.ADDRESS_ABSOLUTE());
                cyclone += 4;
                break;
            /**
             * ******
             * </editor-fold>
             */
            /**
             * <editor-fold defaultstate="collapsed" desc="STY">
             *******
             */
            case 0x84://zero page
                STY(Memory.ADDRESS_ZERO_PAGE());
                cyclone += 3;
                break;
            case 0x94://zero page y
                STY(Memory.ADDRESS_ZERO_PAGE_X());
                cyclone += 4;
                break;
            case 0x8C://absolute
                STY(Memory.ADDRESS_ABSOLUTE());
                cyclone += 4;
                break;
            /**
             * ******
             * </editor-fold>
             */
            /**
             * <editor-fold defaultstate="collapsed" desc="LAX">
             *******
             */
            case 0xA7://zero page
                LAX(Memory.MODE_ZERO_PAGE());
                cyclone += 3;
                break;
            case 0xB7://zero page y
                LAX(Memory.MODE_ZERO_PAGE_Y());
                cyclone += 4;
                break;
            case 0xAF://absolute
                LAX(Memory.MODE_ABSOLUTE());
                cyclone += 4;
                break;
            case 0xBF://absolute y
                LAX(Memory.MODE_ABSOLUTE_Y());
                cyclone += 4;
                turnThePage = 1;
                break;
            case 0xA3://indirect x
                LAX(Memory.MODE_INDIRECT_X());
                cyclone += 6;
                break;
            case 0xB3://indirect y
                LAX(Memory.MODE_INDIRECT_Y());
                cyclone += 5;
                break;
            /**
             * ******
             * </editor-fold>
             */
            /**
             * <editor-fold defaultstate="collapsed" desc="SAX">
             *******
             */
            case 0x87://zero page
                SAX(Memory.ADDRESS_ZERO_PAGE());
                cyclone += 3;
                break;
            case 0x97://zero page X
                SAX(Memory.ADDRESS_ZERO_PAGE_Y());
                cyclone += 4;
                break;
            case 0x8F://absolute
                SAX(Memory.ADDRESS_ABSOLUTE());
                cyclone += 6;
                break;
            case 0x83://indirect X
                SAX(Memory.ADDRESS_INDIRECT_X());
                cyclone += 4;
                break;
            /**
             * ******
             * </editor-fold>
             */
            /**
             * <editor-fold defaultstate="collapsed" desc="DCP">
             *******
             */
            case 0xC7://zero page
                DCP(Memory.ADDRESS_ZERO_PAGE());
                cyclone += 5;
                break;
            case 0xD7://zero page X
                DCP(Memory.ADDRESS_ZERO_PAGE_X());
                cyclone += 6;
                break;
            case 0xCF://absolute
                DCP(Memory.ADDRESS_ABSOLUTE());
                cyclone += 6;
                break;
            case 0xDF://absolute X
                DCP(Memory.ADDRESS_ABSOLUTE_X());
                cyclone += 7;
                break;
            case 0xDB://absolute y
                DCP(Memory.ADDRESS_ABSOLUTE_Y());
                cyclone += 7;
                break;
            case 0xC3://indirect X
                DCP(Memory.ADDRESS_INDIRECT_X());
                cyclone += 8;
                break;
            case 0xD3://indirect y
                DCP(Memory.ADDRESS_INDIRECT_Y());
                cyclone += 8;
                break;
            /**
             * ******
             * </editor-fold>
             */
            /**
             * <editor-fold defaultstate="collapsed" desc="ISB">
             *******
             */
            case 0xE7://zero page
                ISB(Memory.ADDRESS_ZERO_PAGE());
                cyclone += 5;
                break;
            case 0xF7://zero page X
                ISB(Memory.ADDRESS_ZERO_PAGE_X());
                cyclone += 6;
                break;
            case 0xEF://absolute
                ISB(Memory.ADDRESS_ABSOLUTE());
                cyclone += 6;
                break;
            case 0xFF://absolute X
                ISB(Memory.ADDRESS_ABSOLUTE_X());
                cyclone += 7;
                break;
            case 0xFB://absolute y
                ISB(Memory.ADDRESS_ABSOLUTE_Y());
                cyclone += 7;
                break;
            case 0xE3://indirect X
                ISB(Memory.ADDRESS_INDIRECT_X());
                cyclone += 8;
                break;
            case 0xF3://indirect y
                ISB(Memory.ADDRESS_INDIRECT_Y());
                cyclone += 8;
                break;
            /**
             * ******
             * </editor-fold>
             */
            /**
             * <editor-fold defaultstate="collapsed" desc="SLO">
             *******
             */
            case 0x07://zero page
                SLO(Memory.ADDRESS_ZERO_PAGE());
                cyclone += 5;
                break;
            case 0x17://zero page X
                SLO(Memory.ADDRESS_ZERO_PAGE_X());
                cyclone += 6;
                break;
            case 0x0F://absolute
                SLO(Memory.ADDRESS_ABSOLUTE());
                cyclone += 6;
                break;
            case 0x1F://absolute X
                SLO(Memory.ADDRESS_ABSOLUTE_X());
                cyclone += 7;
                break;
            case 0x1B://absolute y
                SLO(Memory.ADDRESS_ABSOLUTE_Y());
                cyclone += 7;
                break;
            case 0x03://indirect X
                SLO(Memory.ADDRESS_INDIRECT_X());
                cyclone += 8;
                break;
            case 0x13://indirect y
                SLO(Memory.ADDRESS_INDIRECT_Y());
                cyclone += 8;
                break;
            /**
             * ******
             * </editor-fold>
             */
            /**
             * <editor-fold defaultstate="collapsed" desc="RLA">
             *******
             */
            case 0x27://zero page
                RLA(Memory.ADDRESS_ZERO_PAGE());
                cyclone += 5;
                break;
            case 0x37://zero page X
                RLA(Memory.ADDRESS_ZERO_PAGE_X());
                cyclone += 6;
                break;
            case 0x2F://absolute
                RLA(Memory.ADDRESS_ABSOLUTE());
                cyclone += 6;
                break;
            case 0x3F://absolute X
                RLA(Memory.ADDRESS_ABSOLUTE_X());
                cyclone += 7;
                break;
            case 0x3B://absolute y
                RLA(Memory.ADDRESS_ABSOLUTE_Y());
                cyclone += 7;
                break;
            case 0x23://indirect X
                RLA(Memory.ADDRESS_INDIRECT_X());
                cyclone += 8;
                break;
            case 0x33://indirect y
                RLA(Memory.ADDRESS_INDIRECT_Y());
                cyclone += 8;
                break;
            /**
             * ******
             * </editor-fold>
             */
            /**
             * <editor-fold defaultstate="collapsed" desc="SRE">
             *******
             */
            case 0x47://zero page
                SRE(Memory.ADDRESS_ZERO_PAGE());
                cyclone += 5;
                break;
            case 0x57://zero page X
                SRE(Memory.ADDRESS_ZERO_PAGE_X());
                cyclone += 6;
                break;
            case 0x4F://absolute
                SRE(Memory.ADDRESS_ABSOLUTE());
                cyclone += 6;
                break;
            case 0x5F://absolute X
                SRE(Memory.ADDRESS_ABSOLUTE_X());
                cyclone += 7;
                break;
            case 0x5B://absolute y
                SRE(Memory.ADDRESS_ABSOLUTE_Y());
                cyclone += 7;
                break;
            case 0x43://indirect X
                SRE(Memory.ADDRESS_INDIRECT_X());
                cyclone += 8;
                break;
            case 0x53://indirect y
                SRE(Memory.ADDRESS_INDIRECT_Y());
                cyclone += 8;
                break;
            /**
             * ******
             * </editor-fold>
             */
            /**
             * <editor-fold defaultstate="collapsed" desc="RRA">
             *******
             */
            case 0x67://zero page
                RRA(Memory.ADDRESS_ZERO_PAGE());
                cyclone += 5;
                break;
            case 0x77://zero page X
                RRA(Memory.ADDRESS_ZERO_PAGE_X());
                cyclone += 6;
                break;
            case 0x6F://absolute
                RRA(Memory.ADDRESS_ABSOLUTE());
                cyclone += 6;
                break;
            case 0x7F://absolute X
                RRA(Memory.ADDRESS_ABSOLUTE_X());
                cyclone += 7;
                break;
            case 0x7B://absolute y
                RRA(Memory.ADDRESS_ABSOLUTE_Y());
                cyclone += 7;
                break;
            case 0x63://indirect X
                RRA(Memory.ADDRESS_INDIRECT_X());
                cyclone += 8;
                break;
            case 0x73://indirect y
                RRA(Memory.ADDRESS_INDIRECT_Y());
                cyclone += 8;
                break;
            /**
             * ******
             * </editor-fold>
             */
            /**
             * <editor-fold defaultstate="collapsed" desc="AAC">
             *******
             */
            case 0x0B:
            case 0x2B:
                AAC(Memory.MODE_IMMEDIATE());
                cyclone += 2;
                break;
            /**
             * ******
             * </editor-fold>
             */
            /**
             * <editor-fold defaultstate="collapsed" desc="ASR">
             *******
             */
            case 0x4B:
                ASR(Memory.MODE_IMMEDIATE());
                cyclone += 2;
                break;
            /**
             * ******
             * </editor-fold>
             */
            /**
             * <editor-fold defaultstate="collapsed" desc="ARR">
             *******
             */
            case 0x6B:
                ARR(Memory.MODE_IMMEDIATE());
                cyclone += 2;
                break;
            /**
             * ******
             * </editor-fold>
             */
            /**
             * <editor-fold defaultstate="collapsed" desc="ATX">
             *******
             */
            case 0xAB:
                ATX(Memory.MODE_IMMEDIATE());
                cyclone += 2;
                break;
            /**
             * ******
             * </editor-fold>
             */
            /**
             * <editor-fold defaultstate="collapsed" desc="AXS">
             *******
             */
            case 0xCB:
                AXS(Memory.MODE_IMMEDIATE());
                cyclone += 2;
                break;
            /**
             * ******
             * </editor-fold>
             */
            /**
             * <editor-fold defaultstate="collapsed" desc="SXYA">
             *******
             */
            case 0x9C:
                SYA(Memory.ADDRESS_ABSOLUTE_X());
                cyclone += 5;
                break;
            case 0x9E:
                SXA(Memory.ADDRESS_ABSOLUTE_Y());
                cyclone += 5;
                break;
            /**
             * ******
             * </editor-fold>
             */
            default:
//                MainUI.forceFPS();
                throw new Exception(" Unidentified Flying Opcode 0x" + Integer.toHexString(opcode & 0xFF) + " @" + Registers.PC);
        }
        //default PC++/////////////////
    }

    /**
     * ADd with Carry @flags NVZC
     */
    private void ADC(short constant) {
        final byte A = Registers.A;
        final int result = (A & 0xFF) + (constant & 0xFF) + Flags.C;
        Registers.A = (byte) result;

        Flags.setCarryFlag((short) result);
        Flags.setZeroFlag(Registers.A);
        Flags.setOverflowFlag(A, (byte) constant, Registers.A);
        Flags.setNegativeFlag(Registers.A);

        //position after nextByte
        Registers.PC++;
    }

    /**
     * bitwise AND with accumulator
     */
    private void AND(short constant) {
        Registers.A &= constant;

        Flags.setZeroFlag(Registers.A);

        Flags.setNegativeFlag(Registers.A);

        Registers.PC++;
    }

    /**
     * Arithmetic Shift Left
     */
    private void ASL(short address) {
        int msb = 0;
        short zero = 0;

        if (MODE_ACCUMULATOR) {
            msb = (Registers.A & 0b1000_0000);//1 if msb is 1
            zero = (Registers.A = (byte) ((Registers.A & 0xFF) << 1));
            MODE_ACCUMULATOR = false;
        } else {
            msb = (Memory.readByte(address) & 0b1000_0000);
            zero = Memory.writeByte(address, (byte) ((Memory.readByte(address) & 0xFF) << 1));
        }

        Flags.C = (byte) (msb >> 7);
        Flags.setZeroFlag(zero);
        Flags.setNegativeFlag(zero);

        Registers.PC++;
    }

    /**
     * Branch if Carry Clear
     */
    private void BCC(short constant) {
        if (Flags.C == 0) {//carry flag clear?
            Registers.PC += constant;
            ++cyclone;
        }
        Registers.PC++;
    }

    /**
     * Branch if Carry Set
     */
    private void BCS(short constant) {
        if ((Flags.C & 1) == 1) {//carry flag set?
            Registers.PC += constant;
            ++cyclone;
        }
        Registers.PC++;
    }

    /**
     * Branch if EQual
     */
    private void BEQ(short constant) {
        if (Flags.Z) {//equal flag set?
            Registers.PC += constant;
            ++cyclone;
        }
        Registers.PC++;
    }

    /**
     * Branch if Not Equal
     */
    private void BNE(short constant) {
        if (!Flags.Z) {//equal flag clear?
            Registers.PC += constant;
            ++cyclone;
        }
        Registers.PC++;
    }

    /**
     * Branch if MInus
     */
    private void BMI(short constant) {
        if (Flags.N) {//negative flag set?
            Registers.PC += constant;
            ++cyclone;
        }
        Registers.PC++;
    }

    /**
     * Branch if Positive
     */
    private void BPL(short constant) {
        if (!Flags.N) {//negative flag clear?
            Registers.PC += constant;
            ++cyclone;
        }
        Registers.PC++;
    }

    /**
     * Branch if oVerflow Clear
     */
    private void BVC(short constant) {
        if (!Flags.V) {//overflow flag clear?
            Registers.PC += constant;
            ++cyclone;
        }
        Registers.PC++;
    }

    /**
     * Branch if oVerflow Set
     */
    private void BVS(short constant) {
        if (Flags.V) {//overflow flag set?
            Registers.PC += constant;
            ++cyclone;
        }
        Registers.PC++;
    }

    /**
     * BIt Test
     */
    private void BIT(short constant) {
        //is sum zero?
        Flags.setZeroFlag((short) (constant & Registers.A));
        //set to bit 6
        Flags.V = (constant & 0x40) == 0x40;//TODO:use binary bitmask
        //set to bit 7
        Flags.N = (constant & 0x80) == 0x80;

        Registers.PC++;
    }

    /**
     * Force Interrupt BReaK
     */
    private void BRK() {
        Flags.B = true;
        Stack.pushWideSP(Registers.PC += 2);//BRK is 2 wide
        Stack.pushSP(Registers.getP());
        Flags.I = true;//thank you blargg!!
        Registers.PC = (short) 0xFFFD;//0xFFFE - 1, because Memory.ADDRESS_ABSOLUTE() does a pre-increment
        Registers.PC = Memory.ADDRESS_ABSOLUTE();
    }

    /**
     * CLear Carry flag
     */
    private void CLC() {
        //clear carry flag
        Flags.C = 0x0;

        Registers.PC++;
    }

    /**
     * CLear Decimal mode
     */
    private void CLD() {
        //clear decimal flag
        Flags.D = false;

        Registers.PC++;
    }

    /**
     * CLear Interrupt disable
     */
    private void CLI() {
        //clear interrupt disable flag
        Flags.I = false;

        Registers.PC++;
    }

    /**
     * CLear oVerflow flag
     */
    private void CLV() {
        //clear overflow flag
        Flags.V = false;

        Registers.PC++;
    }

    /**
     * Compare
     */
    private void CMP(short constant) {
        short temp = this.subtract(Registers.A, constant);

        Flags.setZeroFlag(temp);
        Flags.setNegativeFlag(temp);
        if ((Registers.A & 0xFF) >= (constant & 0xFF)) {
            Flags.C = 1;
        } else {
            Flags.C = 0;
        }

        Registers.PC++;
    }

    /**
     * ComPare X register
     */
    private void CPX(short constant) {
        short temp = this.subtract(Registers.X, constant);

        Flags.setZeroFlag(temp);
        Flags.setNegativeFlag(temp);
        if ((Registers.X & 0xFF) >= (constant & 0xFF)) {
            Flags.C = 1;
        } else {
            Flags.C = 0;
        }

        Registers.PC++;
    }

    /**
     * ComPare Y register
     */
    private void CPY(short constant) {
        short temp = this.subtract(Registers.Y, constant);

        Flags.setZeroFlag(temp);
        Flags.setNegativeFlag(temp);
        if ((Registers.Y & 0xFF) >= (constant & 0xFF)) {
            Flags.C = 1;
        } else {
            Flags.C = 0;
        }

        Registers.PC++;
    }

    /**
     * DECrement memory
     */
    private void DEC(short address) {
        byte temp = Memory.readByte(address);
        Flags.setZeroFlag(Memory.writeByte(address, --temp));
        Flags.setNegativeFlag(Memory.readByte(address));

        Registers.PC++;
    }

    /**
     * DEcrement X register
     */
    private void DEX() {
        Flags.setZeroFlag(--Registers.X);
        Flags.setNegativeFlag(Registers.X);

        Registers.PC++;
    }

    /**
     * DEcrement Y register
     */
    private void DEY() {
        Flags.setZeroFlag(--Registers.Y);
        Flags.setNegativeFlag(Registers.Y);

        Registers.PC++;
    }

    /**
     * Exclusive OR
     */
    private void EOR(short constant) {
        Registers.A ^= constant;
        Flags.setZeroFlag(Registers.A);
        Flags.setNegativeFlag(Registers.A);

        Registers.PC++;
    }

    /**
     * INCrement memory
     */
    private void INC(short address) {//you heard me..constat..NOT constant!
        byte temp = Memory.readByte(address);
        Flags.setZeroFlag(Memory.writeByte(address, ++temp));
        Flags.setNegativeFlag(Memory.readByte(address));

        Registers.PC++;
    }

    /**
     * INcrement X register
     */
    private void INX() {
        Flags.setZeroFlag(++Registers.X);
        Flags.setNegativeFlag(Registers.X);

        Registers.PC++;
    }

    /**
     * INcrement Y register
     */
    private void INY() {
        Flags.setZeroFlag(++Registers.Y);
        Flags.setNegativeFlag(Registers.Y);

        Registers.PC++;
    }

    /**
     * JuMP
     */
    private void JMP(short address) {
        //TODO:page boundry fetch bug?
        Registers.PC = address;
    }

    /**
     * Jump to SubRoutine
     */
    private void JSR(short address) {
        Stack.pushWideSP(Registers.PC);
        Registers.PC = address;
    }

    /**
     * LoaD Accumulator
     */
    private void LDA(short constat) {
        Registers.A = (byte) constat;
        Flags.setZeroFlag(Registers.A);
        Flags.setNegativeFlag(Registers.A);

        Registers.PC++;
    }

    /**
     * LoaD X register
     */
    private void LDX(short constat) {
        Registers.X = (byte) constat;
        Flags.setZeroFlag(Registers.X);
        Flags.setNegativeFlag(Registers.X);

        Registers.PC++;
    }

    /**
     * LoaD Y register
     */
    private void LDY(short constat) {
        Registers.Y = (byte) constat;
        Flags.setZeroFlag(Registers.Y);
        Flags.setNegativeFlag(Registers.Y);

        Registers.PC++;
    }
    private boolean MODE_ACCUMULATOR = false;

    /**
     * Logical Shift Right
     */
    private void LSR(short address) {
        //clear flags unconditionally
        Flags.N = false;

        int lsb = 0;
        short zero = 0;

        if (MODE_ACCUMULATOR) {
            lsb = Registers.A & 0b0000_0001;
            //TODO:maybe use >>> instead of (&0xFF and >>)
            zero = (Registers.A = (byte) ((Registers.A & 0xFF) >> 1));
            MODE_ACCUMULATOR = false;
        } else {
            lsb = Memory.readByte(address) & 0b0000_0001;
            zero = Memory.writeByte(address, (byte) ((Memory.readByte(address) & 0xFF) >> 1));
        }

        Flags.C = (byte) lsb;
        Flags.setZeroFlag(zero);

        Registers.PC++;
    }

    /**
     * No OPeration
     */
    private void NOP() {
        Registers.PC++;
    }

    /**
     * bitwise OR with Accumulator
     */
    private void ORA(short constat) {
        Registers.A = (byte) (constat | Registers.A);
        Flags.setZeroFlag(Registers.A);
        Flags.setNegativeFlag(Registers.A);

        Registers.PC++;
    }

    /**
     * PusH Accumulator
     */
    private void PHA() {
        Stack.pushSP(Registers.A);

        Registers.PC++;
    }

    /**
     * Push Processor Status
     */
    private void PHP() {
        Flags.B = true;
        Stack.pushSP(Registers.getP());

        Registers.PC++;
    }

    /**
     * PulL Accumulator
     */
    private void PLA() {
        Registers.A = Stack.popSP();
        Flags.setZeroFlag(Registers.A);
        Flags.setNegativeFlag(Registers.A);

        Registers.PC++;
    }

    /**
     * PulL Processor status
     */
    private void PLP() {
        Registers.setP(Stack.popSP());

        Registers.PC++;
    }

    /**
     * ROtate Left
     */
    private void ROL(short address) {
        int old_carry = Flags.C;
        int msb = 0;

        short zero = 0;

        if (MODE_ACCUMULATOR) {
            MODE_ACCUMULATOR = false;
            msb = Registers.A & 0b1000_0000;
            zero = (Registers.A = (byte) (((Registers.A & 0xFF) << 1) + old_carry));
        } else {
            //TODO:check if address can be larger than 0xFF
            msb = Memory.readByte(address) & 0b1000_0000;
            zero = Memory.writeByte(address, (byte) (((Memory.readByte(address) & 0xFF) << 1) + old_carry));
        }

        Flags.C = (byte) (msb >> 7);
        Flags.setZeroFlag(zero);
        Flags.setNegativeFlag(zero);

        Registers.PC++;
    }

    /**
     * ROtate Right aka:Repeat On Rinse
     */
    private void ROR(short address) {
        int old_carry = (Flags.C << 7);//make old carry bit ready for insertion into location 7 e.g. 0b00000001 => 0b10000000
        int lsb = 0;

        short zero = 0;

        if (MODE_ACCUMULATOR) {
            MODE_ACCUMULATOR = false;
            lsb = Registers.A & 0b0000_0001;
            zero = (Registers.A = (byte) (((Registers.A & 0xFF) >> 1) + old_carry));
        } else {
            lsb = Memory.readByte(address) & 0b0000_0001;
            zero = Memory.writeByte(address, (byte) (((Memory.readByte(address) & 0xFF) >> 1) + old_carry));
        }

        Flags.C = (byte) lsb;
        Flags.setZeroFlag(zero);
        Flags.setNegativeFlag(zero);

        Registers.PC++;
    }

    /**
     * ReTurn from Interrupt
     */
    private void RTI() {
        Registers.setP(Stack.popSP());
        Registers.PC = Stack.popWideSP();
    }

    /**
     * ReTurn from Subroutine
     */
    private void RTS() {
        Registers.PC = Stack.popWideSP();
        Registers.PC++;
    }

    /**
     * SuBtract with Carry
     */
    private void SBC(short constat) {
        final int result = ((Registers.A & 0xFF) + ~(constat & 0xFF) + Flags.C);//subtract NOT carry flag

        Flags.setOverflowFlag(Registers.A, (byte) ~(byte) (constat), (byte) result);
        Registers.A = (byte) result;
        Flags.setNotCarryFlag((short) result);
        Flags.setZeroFlag(Registers.A);
        Flags.setNegativeFlag(Registers.A);

        Registers.PC++;
    }

    /**
     * SEt Carry flag
     */
    private void SEC() {
        //set carry flag
        Flags.C = 0x1;

        Registers.PC++;
    }

    /**
     * SEt Decimal mode
     */
    private void SED() {
        //set decimal flag
        Flags.D = true;

        Registers.PC++;
    }

    /**
     * SEt Interrupt disable
     */
    private void SEI() {
        //set interrupt disable flag
        Flags.I = true;

        Registers.PC++;
    }

    /**
     * SEt oVerflow flag
     */
    private void SEV() {
        //set overflow flag
        Flags.V = true;

        Registers.PC++;
    }

    /**
     * STore Accumulator
     */
    private void STA(short address) {
        Memory.writeByte(address, Registers.A);

        Registers.PC++;
    }

    /**
     * STore X register
     */
    private void STX(short address) {
        Memory.writeByte(address, Registers.X);

        Registers.PC++;
    }

    /**
     * STore Y register
     */
    private void STY(short address) {
        Memory.writeByte(address, Registers.Y);

        Registers.PC++;
    }

    /**
     * Transfer A to X
     */
    private void TAX() {
        Registers.X = Registers.A;

        Flags.setZeroFlag(Registers.X);//TODO:check A instead of X for compiler concurrency?
        Flags.setNegativeFlag(Registers.X);

        Registers.PC++;
    }

    /**
     * Transfer A to Y
     */
    private void TAY() {
        Registers.Y = Registers.A;

        Flags.setZeroFlag(Registers.Y);
        Flags.setNegativeFlag(Registers.Y);

        Registers.PC++;
    }

    /**
     * Transfer Stack pointer to X
     */
    private void TSX() {
        Registers.X = Stack.getSP();

        Flags.setZeroFlag(Registers.X);
        Flags.setNegativeFlag(Registers.X);

        Registers.PC++;
    }

    /**
     * Transfer X to Accumulator
     */
    private void TXA() {
        Registers.A = Registers.X;

        Flags.setZeroFlag(Registers.A);
        Flags.setNegativeFlag(Registers.A);

        Registers.PC++;
    }

    /**
     * Transfer X to Stack pointer
     */
    private void TXS() {//TODO:double single address check
        Stack.setSP(Registers.X);

        Registers.PC++;
    }

    /**
     * Transfer Y to Accumulator
     */
    private void TYA() {
        Registers.A = Registers.Y;

        Flags.setZeroFlag(Registers.A);
        Flags.setNegativeFlag(Registers.A);

        Registers.PC++;
    }

    /**
     * U T I L
     */
    private short subtract(short register, short constant) {
        return (short) (register - constant);
//        return (short) ((register & 0xFF) - (constant & 0xFF));
        //two's compliment + 1
//        return (short) (register + (~(constant)) + 1);
    }

    /**
     *
     *
     * U N D O C U M E N T E D O P C O D E S
     * http://ffd2.com/fridge/docs/6502-NMOS.extra.opcodes
     *
     *
     */
    /**
     * Double no OPeration
     */
    private void DOP() {
        NOP();
        NOP();
    }

    /**
     * <b>L</b>oad Accumulator and X register
     */
    private void LAX(short constant) {
        this.LDA(constant);
        this.LDX(constant);
        Registers.PC--;//only one pc movement
    }

    /**
     * Store Accumulator and X register
     */
    private void SAX(short address) {
        Memory.writeByte(address, (byte) (Registers.A & Registers.X));
        Registers.PC++;
    }

    /**
     * Decrement and ComPare
     */
    private void DCP(short address) {
        this.CMP(Memory.writeByte(address, ((byte) (Memory.readByte(address) - 1))));
    }

    /**
     * Increase and SuBtract
     */
    private void ISB(short address) {
        this.INC(address);
        byte temp = Memory.readByte(address);
        Registers.PC--;
        this.SBC(temp);
    }

    /**
     * Shift Left and Or accumulator
     */
    private void SLO(short address) {
        byte temp = Memory.readByte(address);
        int carry = (temp & 0b1000_0000) >> 7;
        byte constat = (Memory.writeByte(address, ((byte) (temp << 1))));
        Registers.A |= constat;
        Flags.setNegativeFlag(Registers.A);
        Flags.setZeroFlag(Registers.A);
        Flags.C = (byte) carry;
        Registers.PC++;
    }

    /**
     * Rotate Left and Accumulator
     */
    private void RLA(short address) {
        int old_carry = Flags.C;
        byte constat = Memory.readByte(address);
        int msb = (constat & 0b1000_0000) >> 7;

        constat = (byte) ((constat << 1) + old_carry);
        Memory.writeByte(address, constat);

        Registers.A &= constat;
        Flags.setNegativeFlag(Registers.A);
        Flags.setZeroFlag(Registers.A);
        Flags.C = (byte) msb;
        Registers.PC++;
        Registers.getP();
    }

    /**
     * Shift Right then EOR
     */
    private void SRE(short address) {
        short temp = (short) (Memory.readByte(address) & 0xFF);
        int lsb = temp & 0b0000_0001;

        byte constat = (byte) (temp >>= 1);
        Registers.A ^= constat;
        Memory.writeByte(address, constat);
        Flags.setNegativeFlag(Registers.A);
        Flags.setZeroFlag(Registers.A);
        Flags.C = (byte) lsb;
        Registers.PC++;
        Registers.getP();
    }

    /**
     * Rotate Right and Add to accumulator
     */
    private void RRA(short address) {
        ROR(address);
        short temp = (short) (Memory.readByte(address) & 0xFF);
        Registers.PC--;
        ADC(temp);
    }

    /**
     * And ACcumulator
     */
    private void AAC(short constant) {
        Registers.A &= constant;
        Flags.setZeroFlag(Registers.A);
        Flags.setCarryFlag(Registers.A);
        Flags.setNegativeFlag(Registers.A);
        Registers.PC++;
    }

    /**
     * And accumulator then Shift Right
     */
    private void ASR(short constant) {
        Registers.A &= constant;
        byte lsb = (byte) (Registers.A & 1);
        Registers.A = (byte) ((Registers.A & 0xFF) >> 1);

        Flags.setNegativeFlag(Registers.A);
        Flags.setZeroFlag(Registers.A);
        Flags.C = lsb;
        Registers.PC++;
    }

    /**
     * And accumulator then RoR
     */
    private void ARR(short constant) {
        Registers.A &= constant;
        Registers.A = (byte) ((Registers.A & 0xFF) >> 1);
        Registers.A |= (Flags.C == 1 ? 128 : 0);

        boolean bit5 = (Registers.A & 0b0010_0000) > 0;
        boolean bit6 = (Registers.A & 0b0100_0000) > 0;

        Flags.V = (bit5 ^ bit6);
        Flags.C = (byte) (bit6 ? 1 : 0);
        Flags.setZeroFlag(Registers.A);
        Flags.setNegativeFlag(Registers.A);
        Registers.PC++;
    }

    /**
     * load A Then X
     */
    private void ATX(short constant) {
        Registers.X = Registers.A = (byte) constant;
        Flags.setNegativeFlag(Registers.X);
        Flags.setZeroFlag(Registers.X);
        Registers.PC++;
    }

    /**
     * And X register with accumulator and Subtract byte @aka SAX
     */
    private void AXS(short constant) {
        final short result = (short) (((Registers.A & 0xFF) & (Registers.X & 0xFF)) - (constant & 0xFF));
        Registers.X = (byte) (result & 0xff);
        Flags.setZeroFlag(result);
        Flags.C = (byte) (result >= 0 ? 1 : 0);//reverse carry flag
        Flags.setNegativeFlag(result);
        Registers.PC++;
    }

    private void SYA(short address) {
        byte highByte = (byte) (address >> 8);
        byte lowByte = (byte) ((address - (Registers.X & 0xFF)) & 0xFF);//

        if (((Registers.X & 0xFF) + (lowByte & 0xFF)) <= 0xFF) {//only write if page boundry not crossed
            Memory.writeByte(address, (byte) ((Registers.Y & 0xFF) & ((highByte + 1) & 0xFF)));
        }
        Registers.PC++;
    }

    private void SXA(short address) {
        byte highByte = (byte) (address >> 8);

        //this does the same as SYA
        if (((Registers.Y & 0xFF) + ((Memory.readByte(Registers.getUnsignerPC() - 1)) & 0xFF)) <= 0xFF) {
            Memory.writeByte(address, (byte) ((Registers.X & 0xFF) & ((highByte + 1) & 0xFF)));
        }
        Registers.PC++;
    }
    //SBC,DCP,ISB,SLO,RLA,SRE,RRA
}
